package com.omega.encryptedsql.utils;

/**
 * @author omega
 * @description: TODO
 * @date 2025/7/12
 */
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.*;
import java.util.stream.Stream;

public class EntityClassExtractor {

    // 已知的实体类key（根据项目规范添加）
    private static final Set<String> ENTITY_KEYS = new HashSet<>(Arrays.asList(
            "entity", "record", "data", "param", "value", "model", "vo", "dto"
    ));

    /**
     * 从Map中提取实体类
     */
    public static Class<?> extractEntityClass(Map<?, ?> paramMap) {
        if (paramMap == null || paramMap.isEmpty()) return null;

        // 1. 尝试直接获取实体类对象
        Object entityObj = findEntityObject(paramMap);
        if (entityObj instanceof Optional<?> &&  ((Optional<?>) entityObj).isPresent()) {
            return getEntityClass(((Optional<?>) entityObj).get());
        }

        // 2. 尝试从分页对象中提取
        Optional<Class<?>> pageEntity = extractFromPage(paramMap);
        if (pageEntity.isPresent()) {
            return pageEntity.get();
        }

        // 3. 尝试从集合中提取
        Optional<Class<?>> collectionEntity = extractFromCollection(paramMap);
        return collectionEntity.orElse(null);

    }

    /**
     * 获取实体类（处理代理）
     */
    private static Class<?> getEntityClass(Object obj) {
        if (obj == null) return null;

        // 处理 Spring 代理
        if (obj.getClass().getName().contains("$$")) {
            // CGLIB 代理
            if (obj.getClass().getName().contains("EnhancerBySpringCGLIB")) {
                return obj.getClass().getSuperclass();
            }
            // JDK 动态代理
            return Arrays.stream(obj.getClass().getInterfaces())
                    .filter(EntityClassExtractor::isEntityClass)
                    .findFirst()
                    .orElse(obj.getClass());
        }
        return obj.getClass();
    }

    /**
     * 查找可能的实体对象
     */
    private static Object findEntityObject(Map<?, ?> paramMap) {
        // 策略1：按已知key查找
        for (String key : ENTITY_KEYS) {
            if (paramMap.containsKey(key)) {
                Object candidate = paramMap.get(key);
                if (candidate != null && isEntityClass(candidate.getClass())) {
                    return candidate;
                }
            }
        }

        // 策略2：按值类型查找
        return paramMap.values().stream()
                .filter(Objects::nonNull)
                .filter(v -> isEntityClass(v.getClass()))
                .findFirst();
    }

    /**
     * 从分页对象提取实体类
     */
    private static Optional<Class<?>> extractFromPage(Map<?, ?> paramMap) {
        return paramMap.values().stream()
                .filter(Objects::nonNull)
                .filter(v -> v instanceof IPage)
                .findFirst()
                .map(page -> {
                    try {
                        // 获取分页记录
                        List<?> records = (List<?>) ((IPage<?>) page).getRecords();
                        if (!records.isEmpty()) {
                            return getEntityClass(records.get(0));
                        }
                    } catch (Exception e) {
                        // 忽略异常
                    }
                    return null;
                });
    }

    /**
     * 从集合中提取实体类
     */
    private static Optional<Class<?>> extractFromCollection(Map<?, ?> paramMap) {
        return paramMap.values().stream()
                .filter(Objects::nonNull)
                .filter(v -> v instanceof Collection)
                .map(Collection.class::cast)
                .filter(coll -> !coll.isEmpty())
                .findFirst()
                .map(coll -> getEntityClass(coll.iterator().next()));
    }

    /**
     * 判断是否是实体类（自定义规则）
     */
    private static boolean isEntityClass(Class<?> clazz) {
        // 规则1：排除JDK内置类型
        if (clazz.getName().startsWith("java.")) return false;
        if (clazz.getName().startsWith("javax.")) return false;

        // 规则2：检查包路径（根据项目规范调整）
        String pkg = clazz.getPackage().getName();
        if (pkg.contains(".entity.")) return true;
        if (pkg.contains(".model.")) return true;
        if (pkg.contains(".domain.")) return true;

        // 规则3：检查注解（可选）
        try {
            if (clazz.isAnnotationPresent(TableName.class)) {
                return true;
            }
        } catch (NoClassDefFoundError e) {
            // 忽略
        }

        // 规则4：检查字段特征（有id字段）
        return Stream.of(clazz.getDeclaredFields())
                .anyMatch(f -> "id".equals(f.getName()));
    }

    /**
     * 从MyBatis参数对象提取实体类
     */
    public static Class<?> extractFromParameterObject(Object parameterObject) {
        if (parameterObject == null) return null;

        // 处理Map类型
        if (parameterObject instanceof Map) {
            return extractEntityClass((Map<?, ?>) parameterObject);
        }

        // 处理非Map类型
        return getEntityClass(parameterObject);
    }
}
